package com.shm.toOffer;

/**
 *  发散思维能力	不用加减乘除做加法
 *  题目描述
 * 写一个函数，求两个整数之和，要求在函数体内不得使用+、-、*、/四则运算符号。
 */
public class Add {
    /**
     * 链接：https://www.nowcoder.com/questionTerminal/59ac416b4b944300b617d4f7f111b215?answerType=1&f=discussion
     * 来源：牛客网
     *
     * 1、位运算
     * 1.解题思路
     * 使用位运算实现加法
     *
     * 1、一位加法
     * 普通加法	异或
     * 1 + 1 = 0	1 ^ 1 = 0(错误)
     * 1 + 0 = 1	1 ^ 0 = 1(正确)
     * 0 + 1 = 1	0 ^ 1 = 1(正确)
     * 0 + 0 = 0	0 ^ 0 = 0(正确)
     * 问题：没有采取进位操作导致运算错误
     *
     * 难点：如何解决进位问题？
     *
     * 与运算
     * 1 & 1 = 1(进位)
     * 1 & 0 = 0(不进位)
     * 0 & 1 = 0(不进位)
     * 0 & 0 = 0(不进位)
     * 在位运算中，我们用“<<”表示向左移动一位，也就是“进位”。那么我们就可以得到如下的表达式:
     *
     * ( x & y ) << 1
     * 拥有了两个基本表达式：
     *
     * 执行加法 x ^ y
     * 进位操作 ( x & y ) << 1
     * 2、二位加法
     * 例子：
     *
     * *正确的加法计算：11+01 = 100 *
     * 使用位运算实现二位加法：
     * 按位加法： res1 = 11 ^ 01 = 10
     * 与运算进位： res2 = (11 & 01) << 1 = ( 01 ) << 1 = 010
     * res1 ^ res2 = 10 ^ 010 = 00
     * (10 & 10) << 1 = 100
     * 3、更高位的加法
     * 继续推理可以得出三位数的加法只需重复的计算三次得到第一个表达式的值就是计算出来的结果
     *
     * 三位加法：
     *
     * 101 ^ 111 = 0010 （没有处理进位的加法）
     * (101 & 111) << 1 = 101 << 1 = 1010 （此处得到哪一位需要加上进位，为1的地方表示有进位需要加上）
     *
     * 0010 ^ 1010 = 1000 （没有处理进位的加法 + 进位 = 没有处理进位的加法）
     *
     * (0010 & 1010) << 1 = 0010 << 1 = 00100 （查看是否有新的进位需要处理）
     *
     * 1000 ^ 00100 （没有处理进位的加法 + 进位 = 没有处理进位的加法）
     *
     * (1000 & 00100) << 1 = 00000 << 1 = 000000 (进位为0，所以没有要处理的进位了)
     *
     * 更高位加法：依上边类推
     * @param num1
     * @param num2
     * @return
     */
    public int Add(int num1,int num2) {
        int result = 0;
        int carry = 0;
        do {
            //不带进位的加法
            result = num1 ^ num2;
            //进位
            carry = (num1&num2)<<1;
            num1 = result;
            num2 = carry;
            // 进位不为0则继续执行加法处理进位
        }while (carry != 0);
        return result;
    }
}
